<script setup lang='ts'>
import type { IProductCategoryTreeItem } from '@fl/api/purchase/model/pricing-tool'
import type { CheckboxValueType } from 'element-plus'

import { useAddOrEditProductCategoryTree } from '@fl/api/purchase'
import SubmitBtn from '@fl/components/submit-btn.vue'
import { getTreeDataDepth } from '@fl/utils/tree'
import { cloneDeep } from 'lodash-es'

import { IS_QUOTE_NODE } from './constant'

const props = withDefaults(defineProps<{
    originTreeData: IProductCategoryTreeItem[]
    productId: string
    selectedTreeData: IProductCategoryTreeItem[]
}>(), {
    originTreeData: () => [],
    selectedTreeData: () => [],
})
const visible = defineModel<boolean>('visible', { required: true })

const dialogTitle = '添加分部'

const treeDepth = ref<number>(0)
const treeLayerData = ref<IProductCategoryTreeItem[][]>([])
const treeLayerSelectStatus = ref<number[]>([])
const treeLayerIndeterminateStatus = computed(() => treeLayerData.value.map((_layer, layerIndex) => !currentLayerIsCheckedAll(layerIndex) && !currentLayerIsCheckedNone(layerIndex)))
const treeLayerCheckAllStatus = computed(() => treeLayerData.value.map((_layer, layerIndex) => currentLayerIsCheckedAll(layerIndex)))
const checkedIds = ref<string[][]>([])

const { isPending: isAddOrEditProductCategoryTreePending, mutate: addOrEditProductCategoryTree } = useAddOrEditProductCategoryTree()

const isSubmitLoading = computed(() => isAddOrEditProductCategoryTreePending.value)

// #region UI Listener
function onTreeLayerItemClick(layerIndex: number, itemIndex: number) {
    treeLayerSelectStatus.value[layerIndex] = itemIndex
    refresh()
}

function handleCheckAllChange(layerIndex: number, val: CheckboxValueType) {
    const toChangeIds = treeLayerData.value[layerIndex]
        .filter((item: IProductCategoryTreeItem) => item.isQuote === IS_QUOTE_NODE.IS_QUOTE)
        .map((item: IProductCategoryTreeItem) => item.id)

    updateCheckedIds(toChangeIds, layerIndex, val ? 'add' : 'delete')
    updateCheckedIdsByParent(layerIndex)
    if (!val) {
        for (let i = checkedIds.value.length - 1; i >= 1; i--) {
            const parentIds = checkedIds.value[i - 1]
            if (!parentIds.length) {
                checkedIds.value[i] = []
            }
        }
    }
}

function handleCheckGroupItemChange(layerIndex: number, _val: CheckboxValueType[]) {
    updateCheckedIdsByParent(layerIndex)
}

function onConfirmBtnClick() {
    addOrEditProductCategoryTree(buildNewTreeByChecked(cloneDeep(props.originTreeData!)), {
        onSuccess() {
            ElMessage.success('操作成功')
            cancel()
        },
    })
}

function cancel() {
    visible.value = false
}

function closed() {

}
// #endregion

function updateCheckedIds(toChangeIds: string[], layerIndex: number, type: 'add' | 'delete') {
    const oldIds = checkedIds.value[layerIndex]
    let newIds: string[]
    if (type === 'add') {
        newIds = Array.from(new Set([...oldIds, ...toChangeIds]))
    }
    else {
        newIds = oldIds.filter(id => !toChangeIds.includes(id))
    }
    checkedIds.value[layerIndex] = newIds
}

function updateCheckedIdsByParent(layerIndex: number) {
    if (layerIndex >= 1) {
        const parent = treeLayerData.value[layerIndex - 1][treeLayerSelectStatus.value[layerIndex - 1]]
        if (currentLayerIsCheckedNone(layerIndex) && parent.isQuote === IS_QUOTE_NODE.IS_NOT_QUOTE) {
            updateCheckedIds([parent.id], layerIndex - 1, 'delete')
        }
        else {
            updateCheckedIds([parent.id], layerIndex - 1, 'add')
        }
        updateCheckedIdsByParent(layerIndex - 1)
    }
}

function currentLayerIsCheckedAll(layerIndex: number) {
    const currentCheckedIds = checkedIds.value[layerIndex]
    const currentIds = treeLayerData.value[layerIndex].map((item: any) => item.id)
    return Array.from(new Set([...currentCheckedIds, ...currentIds])).length === currentCheckedIds.length
}

function currentLayerIsCheckedNone(layerIndex: number) {
    const currentCheckedIds = checkedIds.value[layerIndex]
    const currentIds = treeLayerData.value[layerIndex].map((item: any) => item.id)
    return Array.from(new Set([...currentCheckedIds, ...currentIds])).length === currentCheckedIds.length + currentIds.length
}

function getSelectStatusByLayer(layerIndex: number) {
    const originIds = [...Array(treeDepth.value)].map((_item, index) =>
        getTreeNodesAtDepth(props.originTreeData?.[0], index).map(item => item.id))
    for (let i = 0; i < checkedIds.value[layerIndex].length; i++) {
        const item = checkedIds.value[layerIndex][i]
        const findIndex = originIds[layerIndex].findIndex(id => id === item)
        if (findIndex !== -1) {
            return findIndex
        }
    }
    return 0
}

function getTreeNodesAtDepth(node: IProductCategoryTreeItem, depth: number, currentDepth: number = 0) {
    let nodes: IProductCategoryTreeItem[] = []
    if (node) {
        if (currentDepth === depth) {
            nodes.push(node)
        }
        else if (node.children && currentDepth < depth) {
            for (const child of node.children) {
                nodes = nodes.concat(getTreeNodesAtDepth(child, depth, currentDepth + 1))
            }
        }
    }
    return nodes
}

function buildNewTreeByChecked(treeData: IProductCategoryTreeItem[], layerIndex: number = 0) {
    const newTree = Array<IProductCategoryTreeItem>()
    for (const item of treeData) {
        if (checkedIds.value[layerIndex].includes(item.id)) {
            item.cbCategoryId = item.id
            item.productId = props.productId
            newTree.push(item)
        }
        item.children = buildNewTreeByChecked(item.children, layerIndex + 1)
    }
    return newTree
}

function hasCheckedChildren(treeDataItem: IProductCategoryTreeItem, layerIndex: number) {
    const subCheckedIds = checkedIds.value?.[layerIndex + 1]
    if (subCheckedIds?.length) {
        const ids = treeDataItem.children.map(item => item.id)
        const idSet = new Set([...ids, ...subCheckedIds])
        return idSet.size < (ids.length + checkedIds.value[layerIndex + 1].length)
    }
    return false
}

function refresh() {
    let lastLayer = props.originTreeData
    const result = [lastLayer]
    for (let i = 1; i < treeDepth.value; i++) {
        const currentLayer = lastLayer[treeLayerSelectStatus.value[i - 1]]?.children || []
        result.push(currentLayer)
        lastLayer = currentLayer
    }
    treeLayerData.value = result.filter(item => item.length)
}

function opened() {
    treeDepth.value = getTreeDataDepth(props.originTreeData)
    checkedIds.value = [...Array(treeDepth.value)].map((_item, index) =>
        getTreeNodesAtDepth(props.selectedTreeData?.[0], index).map(item => item.cbCategoryId))
    treeLayerSelectStatus.value = [...Array(treeDepth.value)].map((_item, index) => getSelectStatusByLayer(index))
    refresh()
}
</script>

<template>
    <PlusDialog v-model="visible"
                :title="dialogTitle"
                width="1062"
                close-on-press-escape
                @cancel="cancel"
                @closed="closed"
                @opened="opened"
    >
        <div class="h-500 overflow-x-auto">
            <div class="h-480 whitespace-nowrap">
                <div v-for="(layer, layerIndex) in treeLayerData"
                     :key="layer.join(',')"
                     class="divide-solid px-12 py-16 inline-block border-1 border-[#E5E6EB] h-full w-250 align-top overflow-y-auto"
                >
                    <div>
                        <el-checkbox v-model="treeLayerCheckAllStatus[layerIndex]"
                                     :indeterminate="treeLayerIndeterminateStatus[layerIndex]"
                                     class="px-8"
                                     @change="handleCheckAllChange(layerIndex, $event)"
                        >
                            全选
                        </el-checkbox>

                        <el-checkbox-group v-model="checkedIds[layerIndex]"
                                           class="flex flex-col h-full"
                                           @change="handleCheckGroupItemChange(layerIndex, $event)"
                        >
                            <el-checkbox v-for="(item, itemIndex) in layer"
                                         :key="item.id"
                                         :label="item.categoryName"
                                         :value="item.id"
                                         class="px-8 !mr-0"
                                         :class="{ 'bg-[#FFF0F0]': itemIndex === treeLayerSelectStatus[layerIndex] }"
                                         :disabled="item.isQuote === IS_QUOTE_NODE.IS_NOT_QUOTE || hasCheckedChildren(item, layerIndex)"
                            >
                                <p class="leading-[32px] truncate w-194"
                                   :class="{ '!text-[#DA0004]': itemIndex === treeLayerSelectStatus[layerIndex] }"
                                   @click.stop.prevent="onTreeLayerItemClick(layerIndex, itemIndex)"
                                >
                                    {{ item.categoryName }}
                                </p>
                            </el-checkbox>
                        </el-checkbox-group>
                    </div>
                </div>
            </div>
        </div>

        <template #footer>
            <div class="mx-auto mt-30">
                <SubmitBtn type="primary"
                           :loading="isSubmitLoading"
                           @click="onConfirmBtnClick"
                >
                    确认
                </SubmitBtn>

                <el-button @click="cancel">
                    取消
                </el-button>
            </div>
        </template>
    </PlusDialog>
</template>

<style scoped lang="scss">
:deep(.el-form-item--default) {
    margin-bottom: 0;
}
:deep(.vxe-table--body-wrapper) {
    min-height: 48px !important;
}
:deep(.vxe-grid--toolbar-wrapper) {
    display: none;
}
</style>
